package com.tiancheng.trade.settlement.service.settlement.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tiancheng.trade.commom.core.data.PageInfo;
import com.tiancheng.trade.commom.core.data.Result;
import com.tiancheng.trade.commom.web.http.PlatformRequest;
import com.tiancheng.trade.commom.core.utils.DateTimeUtil;
import com.tiancheng.trade.settlement.bo.CouponBillExportBO;
import com.tiancheng.trade.settlement.bo.ExportBO;
import com.tiancheng.trade.settlement.enums.OrderSceneEnum;
import com.tiancheng.trade.settlement.exception.error.BusinessErrorInfoEnum;
import com.tiancheng.trade.settlement.mapper.order.CouponMapper;
import com.tiancheng.trade.settlement.mapper.order.VipEquityMapper;
import com.tiancheng.trade.settlement.mapper.settlement.CouponBillMapper;
import com.tiancheng.trade.settlement.model.order.Coupon;
import com.tiancheng.trade.settlement.model.order.Orders;
import com.tiancheng.trade.settlement.model.order.VipEquity;
import com.tiancheng.trade.settlement.model.payment.PaymentFlow;
import com.tiancheng.trade.settlement.model.settlement.CouponBill;
import com.tiancheng.trade.settlement.service.order.IOrderService;
import com.tiancheng.trade.settlement.service.payment.IPaymentFlowService;
import com.tiancheng.trade.settlement.service.settlement.ICouponBillService;
import com.tiancheng.trade.settlement.util.ExcelUtil;
import com.tiancheng.trade.settlement.util.JsonUtil;
import com.tiancheng.trade.settlement.util.ObjectConvertUtil;
import com.tiancheng.trade.settlement.vo.settlement.admin.CouponBillQueryVO;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.message.BasicHeader;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 优惠券账单
 */
@Service
@Slf4j
public class CouponBillService implements ICouponBillService {

    @Value(value = "${system.coupon.domain}")
    private String couponDomain;
    @Value(value = "${system.coupon.pt-domain}")
    private String ptCouponDomain;

    @Resource
    private CouponBillMapper couponBillMapper;
    @Resource
    private CouponMapper couponMapper;
    @Resource
    private IOrderService orderService;
    @Resource
    private IPaymentFlowService payOrderService;
    @Resource
    private PlatformRequest platformRequest;
    @Resource
    private VipEquityMapper vipEquityMapper;


    @Override
    public void handleCouponBillData(String date) {
        BusinessErrorInfoEnum.QUERY_ARGS_ERROR.assertIsTrue(StringUtils.isNotEmpty(date));
        LocalDateTime start = DateTimeUtil.format(date + " 00:00:00", "yyyy-MM-dd HH:mm:ss");
        LocalDateTime end = DateTimeUtil.format(date + " 23:59:59", "yyyy-MM-dd HH:mm:ss");
        log.info("开始获取微信优惠券订单，start:{},end:{}", start, end);
        int pageSize = 200;
        PageInfo<Orders> page = orderService.findWechatCouponOrders(start, end, 1, pageSize);
        if (page.getPagination().getTotal() == 0) {
            log.info("当前日期条件无微信优惠券订单，start:{},end:{}", start, end);
            return;
        }
        // 把已存在的数据作废
        QueryWrapper<CouponBill> deleteConditions = new QueryWrapper<>();
        final LocalDate now = start.toLocalDate();
        deleteConditions.between("pay_time", LocalDateTime.of(now.getYear(), now.getMonth(), now.getDayOfMonth(), 0, 0, 0),
                LocalDateTime.of(now.getYear(), now.getMonth(), now.getDayOfMonth(), 23, 59, 59));
        couponBillMapper.delete(deleteConditions);

        List<String> errorOrderIds = new ArrayList<>();// 暂时不管错误的订单了，因为从优惠券系统重复取也取不到
        this.getCouponInfo(page.getList(), errorOrderIds);
        long totalPage = page.getPagination().getTotalPage();
        log.info("分页获取微信优惠券订单，第{}页，共{}条", 1, page.getPagination().getTotal());
        for (int i = 1; i < totalPage; i++) {
            PageInfo<Orders> page1 = orderService.findWechatCouponOrders(start, end, i + 1, pageSize);
            log.info("分页获取微信优惠券订单，第{}页，共{}条", i + 1, page1.getPagination().getTotal());
            this.getCouponInfo(page1.getList(), errorOrderIds);
        }

        if (CollectionUtils.isNotEmpty(errorOrderIds)) {
            log.info("重新处理处理失败的订单 orderIds：{}", JsonUtil.toJson(errorOrderIds));
            // 原先没有取到优惠券的订单再试一次
            List<Orders> orders = orderService.findByOrderIds(errorOrderIds);
            this.getCouponInfo(orders, errorOrderIds);
        }
    }

    @Override
    public PageInfo<CouponBill> query(CouponBillQueryVO queryVO) {
        QueryWrapper<CouponBill> conditions = getCouponBillQueryWrapper(queryVO);
        PageInfo<CouponBill> pageInfo = couponBillMapper.find(conditions, queryVO.getCurrentPage(), queryVO.getPageSize());
        if (pageInfo.getPagination().getTotal() > 0) {
            pageInfo.getList().forEach(item -> {
                item.setOrderSourceCn(OrderSceneEnum.getDesc(item.getOrderSource()));
            });
        }
        return pageInfo;
    }

    private QueryWrapper<CouponBill> getCouponBillQueryWrapper(CouponBillQueryVO queryVO) {
        QueryWrapper<CouponBill> conditions = new QueryWrapper<>();
        if (null != queryVO.getCouponType()) {
            conditions.eq("coupon_type", queryVO.getCouponType());
        }
        if (StringUtils.isNotEmpty(queryVO.getOrderId())) {
            conditions.eq("order_id", queryVO.getOrderId());
        }
        conditions.eq("data_status", 1);
        if (StringUtils.isNotEmpty(queryVO.getOrderId())) {
            conditions.eq("order_id", queryVO.getOrderId());
        }
        if (StringUtils.isNotEmpty(queryVO.getCouponNo())) {
            conditions.eq("coupon_no", queryVO.getCouponNo());
        }
        if (StringUtils.isNotEmpty(queryVO.getCouponBatchId())) {
            conditions.eq("coupon_batch_id", queryVO.getCouponBatchId());
        }
        if (StringUtils.isNotEmpty(queryVO.getTransactionId())) {
            conditions.eq("transaction_id", queryVO.getTransactionId());
        }
        if (StringUtils.isNotEmpty(queryVO.getOrderSource())) {
            conditions.eq("order_source", queryVO.getOrderSource());
        }
        if (queryVO.getPayTimeStart() != null) {
            conditions.ge("pay_time", queryVO.getPayTimeStart());
        }
        if (queryVO.getPayTimeEnd() != null) {
            conditions.le("pay_time", queryVO.getPayTimeEnd());
        }
        return conditions;
    }

    @Override
    public Result export(CouponBillQueryVO queryVO, HttpServletRequest request, HttpServletResponse response) throws IllegalAccessException, IOException {
        List<CouponBill> couponBills = this.couponBillMapper.selectList(this.getCouponBillQueryWrapper(queryVO));
        if (CollectionUtils.isNotEmpty(couponBills)) {
            String fileName = "微信优惠券账单.xlsx";
            List<ExportBO> exportBoS = new ArrayList<>();
            String[] allTitleSummary = {"主订单号", "支付流水号", "渠道订单号", "订单名称", "主商户编号", "主商户名称", "支付渠道", "业务渠道", "订单应收金额"
                    , "支付总金额", "优惠总金额", "平台优惠金额", "渠道优惠金额", "支付时间", "券批次", "卡券号", "可用开始时间"
                    , "可用结束时间", "使用门槛", "券类型"};

            List<CouponBillExportBO> collect = new ArrayList<>(couponBills.size());
            couponBills.forEach(s -> collect.add(CouponBillExportBO.build(s)));
            ExportBO exportBoSummary = new ExportBO(fileName.replace(".xlsx", ""), null, allTitleSummary, collect);
            exportBoS.add(exportBoSummary);
            Workbook workbook = ExcelUtil.buildExcelWorkBook(exportBoS);
            ExcelUtil.exportExcle(request, response, workbook, fileName);
            return Result.success("导出成功");
        }
        return Result.success("导出成功");
    }

    /**
     * 查询
     *
     * @param orders        本次查询到的订单
     * @param errorOrderIds 已经存在的未渠道优惠券信息的订单号集合
     */
    private void getCouponInfo(List<Orders> orders, List<String> errorOrderIds) {
        if (CollectionUtils.isEmpty(orders)) {
            return;
        }
        final List<Orders> channelCouponOrders = orders.stream().filter(o -> o.getDiscount() > o.getPlatformDiscount()).collect(Collectors.toList());
        List<CouponBill> insertCouponBills = new ArrayList<>();
        List<CouponBill> deleteCouponBills = new ArrayList<>();

        // 处理渠道优惠券订单
        if (CollectionUtils.isNotEmpty(channelCouponOrders)) {
            List<PaymentFlow> paymentFlows = payOrderService.queryByFlowIds(channelCouponOrders.stream().map(Orders::getFlowId).collect(Collectors.toList()));
            if (CollectionUtils.isEmpty(paymentFlows)) {
                return;
            }
            List<VipEquity> vipEquities = vipEquityMapper.groupByOrderIds(channelCouponOrders.stream().map(Orders::getOrderId).collect(Collectors.toList()));
            if(vipEquities==null){
                vipEquities=new ArrayList<>();
            }
            List<String> collect = paymentFlows.stream().map(PaymentFlow::getTransactionId).collect(Collectors.toList());
            HashMap<String, Object> params = new HashMap<>();
            params.put("orderIds", collect);
            Result result = platformRequest.jsonPostRequest(couponDomain + "api/coupon/getCouponDetail",
                    params, false, this.getTokenHeader());
            log.error("查询优惠券返回:{}", result.toString());
            Map<String, Object> resultMap = JsonUtil.fromJson(result.toString(), Map.class);
            if (MapUtils.getInteger(resultMap, "ret") != null && MapUtils.getInteger(resultMap, "ret").equals(1)) {
                this.errorOrdersHandler(channelCouponOrders, errorOrderIds, paymentFlows, insertCouponBills, 1);
                return;
            }
            List<Map<String, Object>> dataMap = (List<Map<String, Object>>) resultMap.get("data");

            if (CollectionUtils.isNotEmpty(dataMap)) {
                //返回成功,遍历匹配需要写入的数据
                for (Orders order : channelCouponOrders) {
                    PaymentFlow paymentFlow = paymentFlows.stream().filter(p -> p.getFlowId().equals(order.getFlowId())).findFirst().get();
                    final Optional<VipEquity> vo = vipEquities.stream().filter(v -> v.getOrderId().equals(order.getOrderId())).findFirst();
                    Optional<Map<String, Object>> couponOptional = dataMap.stream().filter(d -> MapUtils.getString(d, "orderId").equals(paymentFlow.getTransactionId())).findFirst();
                    CouponBill couponBill = ObjectConvertUtil.convert(order, CouponBill.class).get();
                    couponBill.setId(null);
                    couponBill.setCouponType(1);
                    couponBill.setPayFlowId(order.getFlowId());
                    couponBill.setChannelDiscount(order.getDiscount() - order.getPlatformDiscount());
                    couponBill.setPlatformDiscount(order.getPlatformDiscount());
                    couponBill.setTransactionId(paymentFlow.getTransactionId());
                    Instant instant = order.getPayTime().toInstant();
                    ZoneId zone = ZoneId.systemDefault();
                    couponBill.setPayTime(LocalDateTime.ofInstant(instant, zone));
                    if(vo.isPresent()){
                        couponBill.setVipDiscount(vo.get().getDiscountAmount()+vo.get().getUseBeamAmount());
                    }else{
                        couponBill.setVipDiscount(0);
                    }

                    if (couponOptional.isPresent()) {
                        // 找到优惠券，保存入库
                        couponBill.setCreateDt(LocalDateTime.now());
                        couponBill.setDataStatus(1);
                        couponBill.setCouponBatchId(MapUtils.getString(couponOptional.get(), "couponBatchId"));
                        couponBill.setCouponNo(MapUtils.getString(couponOptional.get(), "couponNo"));
                        String availableStartTime = MapUtils.getString(couponOptional.get(), "availableStartTime");
                        if (StringUtils.isNotEmpty(availableStartTime)) {
                            couponBill.setAvailableStartTime(DateTimeUtil.format(availableStartTime, "yyyy-MM-dd HH:mm:ss"));
                        }
                        String availableEndTime = MapUtils.getString(couponOptional.get(), "availableEndTime");
                        if (StringUtils.isNotEmpty(availableEndTime)) {
                            couponBill.setAvailableEndTime(DateTimeUtil.format(availableEndTime, "yyyy-MM-dd HH:mm:ss"));
                        }
                        couponBill.setMinimum(MapUtils.getString(couponOptional.get(), "minimum"));
                        if (CollectionUtils.isNotEmpty(errorOrderIds) && errorOrderIds.contains(order.getOrderId())) {
                            // 删除原来异常的订单
                            deleteCouponBills.add(couponBill);
                        }
                        insertCouponBills.add(couponBill);
                    } else {
                        // 没找到，标识为异常
                        if (CollectionUtils.isNotEmpty(errorOrderIds) && errorOrderIds.contains(order.getOrderId())) {
                            log.error("还是未查询到订单优惠券信息：order_id:{}", order.getOrderId());
                        } else {
                            couponBill.setCouponBatchId("");
                            couponBill.setCouponNo("");
                            couponBill.setCreateDt(LocalDateTime.now());
                            couponBill.setDataStatus(2);
                            couponBill.setVipDiscount(0);
                            insertCouponBills.add(couponBill);
                        }
                    }
                }
            } else {
                this.errorOrdersHandler(orders, errorOrderIds, paymentFlows, insertCouponBills, 1);
            }
        }
        // 处理平台优惠券订单
        final List<Orders> ptCouponOrders = orders.stream().filter(o -> o.getPlatformDiscount() > 0).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(ptCouponOrders)) {
            final QueryWrapper<Coupon> couponQueryWrapper = new QueryWrapper<>();
            couponQueryWrapper.in("order_id", ptCouponOrders.stream().map(Orders::getOrderId).collect(Collectors.toSet()));
            final List<Coupon> coupons = couponMapper.selectList(couponQueryWrapper);

            List<VipEquity> vipEquities = vipEquityMapper.groupByOrderIds(ptCouponOrders.stream().map(Orders::getOrderId).collect(Collectors.toList()));
            if(vipEquities==null){
                vipEquities=new ArrayList<>();
            }
            if (CollectionUtils.isNotEmpty(coupons)) {
                HashMap<String, Object> params = new HashMap<>();
                params.put("ids", coupons.stream().map(Coupon::getCouponCode).collect(Collectors.toSet()));
                Result result = platformRequest.jsonPostRequest(ptCouponDomain + "api/getCouponDetail",
                        params, false, this.getTokenHeader());
                log.error("查询平台优惠券返回:{}", result.toString());
                Map<String, Object> resultMap = JsonUtil.fromJson(result.toString(), Map.class);

                if (MapUtils.getInteger(resultMap, "ret") != null && MapUtils.getInteger(resultMap, "ret").equals(1)) {
                    this.errorOrdersHandler(ptCouponOrders, errorOrderIds, null, insertCouponBills, 2);
                    return;
                }
                List<Map<String, Object>> dataMap = (List<Map<String, Object>>) resultMap.get("data");
                //返回成功,遍历匹配需要写入的数据
                for (Orders order : ptCouponOrders) {
                    final Optional<Coupon> co = coupons.stream().filter(o -> o.getOrderId().equals(order.getOrderId())).findFirst();
                    final Optional<VipEquity> vo = vipEquities.stream().filter(v -> v.getOrderId().equals(order.getOrderId())).findFirst();
                    Optional<Map<String, Object>> couponOptional=null;
                    if(co.isPresent() && CollectionUtils.isNotEmpty(dataMap)){
                        couponOptional= dataMap.stream().filter(d -> MapUtils.getString(d, "couponNo").equals(co.get().getCouponCode())).findFirst();
                    }

                    CouponBill couponBill = ObjectConvertUtil.convert(order, CouponBill.class).get();
                    couponBill.setId(null);
                    couponBill.setCouponType(2);
                    couponBill.setPayFlowId(order.getFlowId());
                    couponBill.setChannelDiscount(order.getDiscount() - order.getPlatformDiscount());
                    couponBill.setPlatformDiscount(order.getPlatformDiscount());
                    couponBill.setTransactionId(order.getFlowId());
                    if(vo.isPresent()){
                        couponBill.setVipDiscount(vo.get().getDiscountAmount()+vo.get().getUseBeamAmount());
                    }else{
                        couponBill.setVipDiscount(0);
                    }
                    Instant instant = order.getPayTime().toInstant();
                    ZoneId zone = ZoneId.systemDefault();
                    couponBill.setPayTime(LocalDateTime.ofInstant(instant, zone));
                    if (couponOptional!=null && couponOptional.isPresent()) {
                        // 找到优惠券，保存入库
                        couponBill.setCreateDt(LocalDateTime.now());
                        couponBill.setDataStatus(1);
                        couponBill.setCouponBatchId(MapUtils.getString(couponOptional.get(), "couponBatchId"));
                        couponBill.setCouponNo(MapUtils.getString(couponOptional.get(), "couponNo"));
                        String availableStartTime = MapUtils.getString(couponOptional.get(), "availableStartTime");
                        if (StringUtils.isNotEmpty(availableStartTime)) {
                            couponBill.setAvailableStartTime(DateTimeUtil.format(availableStartTime, "yyyy-MM-dd HH:mm:ss"));
                        }
                        String availableEndTime = MapUtils.getString(couponOptional.get(), "availableEndTime");
                        if (StringUtils.isNotEmpty(availableEndTime)) {
                            couponBill.setAvailableEndTime(DateTimeUtil.format(availableEndTime, "yyyy-MM-dd HH:mm:ss"));
                        }
                        if (StringUtils.isNotEmpty(co.get().getCouponName())) {
                            couponBill.setMinimum(co.get().getCouponName());
                        } else {
                            couponBill.setMinimum(MapUtils.getString(couponOptional.get(), "minimum"));
                        }
                        if (CollectionUtils.isNotEmpty(errorOrderIds) && errorOrderIds.contains(order.getOrderId())) {
                            // 删除原来异常的订单
                            deleteCouponBills.add(couponBill);
                        }
                        insertCouponBills.add(couponBill);
                    } else if(vo.isPresent()){
                        // 会员优惠
                        couponBill.setCreateDt(LocalDateTime.now());
                        couponBill.setDataStatus(1);
                        couponBill.setCouponBatchId("");
                        couponBill.setCouponNo("");
                        couponBill.setMinimum("腾云会员优惠");
                        if (CollectionUtils.isNotEmpty(errorOrderIds) && errorOrderIds.contains(order.getOrderId())) {
                            // 删除原来异常的订单
                            deleteCouponBills.add(couponBill);
                        }
                        insertCouponBills.add(couponBill);
                    } else  {
                        // 没找到，标识为异常
                        if (CollectionUtils.isNotEmpty(errorOrderIds) && errorOrderIds.contains(order.getOrderId())) {
                            log.error("还是未查询到订单优惠券信息：order_id:{}", order.getOrderId());
                        } else {
                            couponBill.setCouponBatchId("");
                            couponBill.setCouponNo("");
                            couponBill.setCreateDt(LocalDateTime.now());
                            couponBill.setDataStatus(2);
                            insertCouponBills.add(couponBill);
                        }
                    }
                }
            }else{
                this.handleVipDiscountOrder(errorOrderIds, insertCouponBills, deleteCouponBills, ptCouponOrders, vipEquities);
            }
        }
        // 批量删除
        if (CollectionUtils.isNotEmpty(deleteCouponBills)) {
            couponBillMapper.delete(new QueryWrapper<CouponBill>().in("order_id", deleteCouponBills.stream().map(CouponBill::getOrderId).collect(Collectors.toList())));
        }
        // 批量添加
        if (CollectionUtils.isNotEmpty(insertCouponBills)) {
            couponBillMapper.saveBatch(insertCouponBills);
        }
    }

    private void handleVipDiscountOrder(List<String> errorOrderIds, List<CouponBill> insertCouponBills, List<CouponBill> deleteCouponBills, List<Orders> ptCouponOrders, List<VipEquity> vipEquities) {
        for (Orders order : ptCouponOrders) {
            final VipEquity vipEquity = vipEquities.stream().filter(v -> v.getOrderId().equals(order.getOrderId())).findFirst().get();
            CouponBill couponBill = ObjectConvertUtil.convert(order, CouponBill.class).get();
            couponBill.setId(null);
            couponBill.setCouponType(2);
            couponBill.setPayFlowId(order.getFlowId());
            couponBill.setChannelDiscount(order.getDiscount() - order.getPlatformDiscount());
            couponBill.setPlatformDiscount(order.getPlatformDiscount());
            couponBill.setVipDiscount(vipEquity.getDiscountAmount()+vipEquity.getUseBeamAmount());
            couponBill.setTransactionId(order.getFlowId());
            Instant instant = order.getPayTime().toInstant();
            ZoneId zone = ZoneId.systemDefault();
            couponBill.setPayTime(LocalDateTime.ofInstant(instant, zone));
            couponBill.setCreateDt(LocalDateTime.now());
            couponBill.setDataStatus(1);
            couponBill.setCouponBatchId("");
            couponBill.setCouponNo("");
            couponBill.setMinimum("腾云会员优惠");
            if (CollectionUtils.isNotEmpty(errorOrderIds) && errorOrderIds.contains(order.getOrderId())) {
                // 删除原来异常的订单
                deleteCouponBills.add(couponBill);
            }
            insertCouponBills.add(couponBill);
        }
    }

    private void errorOrdersHandler(List<Orders> orders, List<String> errorOrderIds, List<PaymentFlow> paymentFlows, List<CouponBill> insertCouponBills, int couponType) {
        // 返回数据为空，没查到，需要记录这批次订单为失败，下一个周期继续
        for (Orders order : orders) {
            CouponBill couponBill = ObjectConvertUtil.convert(order, CouponBill.class).get();
            couponBill.setId(null);
            couponBill.setCouponType(couponType);
            couponBill.setDataStatus(2);
            couponBill.setPayFlowId(order.getFlowId());
            couponBill.setChannelDiscount(order.getDiscount() - order.getPlatformDiscount());
            couponBill.setVipDiscount(0);
            if (CollectionUtils.isNotEmpty(paymentFlows)) {
                couponBill.setTransactionId(order.getFlowId());
                paymentFlows.stream().filter(p -> p.getFlowId().equals(order.getFlowId())).findFirst().ifPresent(p->{
                    couponBill.setTransactionId(p.getTransactionId());
                });
            } else {
                couponBill.setTransactionId(order.getFlowId());
            }
            Instant instant = order.getPayTime().toInstant();
            ZoneId zone = ZoneId.systemDefault();
            couponBill.setPayTime(LocalDateTime.ofInstant(instant, zone));
            if (CollectionUtils.isNotEmpty(errorOrderIds) && errorOrderIds.contains(order.getOrderId())) {
                log.error("还是未查询到订单优惠券信息：order_id:{}", order.getOrderId());
            } else {
                couponBill.setCouponBatchId("");
                couponBill.setCouponNo("");
                couponBill.setCreateDt(LocalDateTime.now());
                insertCouponBills.add(couponBill);
            }
        }
    }

    /**
     * 获取优惠券服务的token
     *
     * @return
     */
    private Header getTokenHeader() {
        String token = platformRequest.getAccessToken();
        return new BasicHeader("token", token);
    }
}
